/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - graphics/shaders
// Copyright( c) 2015.  All Rights Reserved
//
// File:		AECompiledEffect.h
// Author:		Gianluca Belardelli
// Date:		31/07/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AECOMPILEDEFFECT_H_
#define _AECOMPILEDEFFECT_H_

/// \brief
///   AECompiledEffect has a collection of shader techniques and provides a mechanism of choosing a specific technique using inclusion and exclusion tags.
///
/// A AECompiledEffect is created from a AEShaderEffectResource (just like a AECompiledTechnique is created from a VShaderEffectTechnique). While AECompiledEffect
/// may, for instance, be used to represent a specific material type (e.g. wood), you might need different ways to render this material type under different
/// conditions (e.g. using directional lighting, using lightmaps, using a point light, etc.). Each of these conditions could be represented as a separate
/// AECompiledTechnique inside the effect, each using different inclusion tags. At runtime, inclusion tags could be used to identify the appropriate technique
/// and render the scene geometry with it.
class AECompiledEffect : public AEReferencedObject
{
// Members
public:
	AECompiledShaderManager &m_refInstanceManager;    ///< reference used to create shader instances
	AEINT32 m_nCachedTechniqueCount;                  ///< same as m_pSourceEffect->m_Techniques.Count();
	AECompiledTechniquePtr *m_spCachedTechniques;  ///< array of size m_nCachedTechniqueCount. Might contain AENULL pointers
	AEShaderEffectResourcePtr m_spSourceEffect;     ///< points to the owner resource
	char *m_lpParamStr;                          ///< parameter string that was used to create this effect instance
	AEINT32 m_nCreationFlags;                         ///< flags used to create this compiled version
	AEBOOL32 m_bDestroying;                           ///< internal flag

// Methods
public:
	/** @name Constructor / Destructor */
	/// @{
	/// \brief
	///   Constructor. For internal use.
	AE_DLLIMPEXP AECompiledEffect( AEShaderEffectResource *lpSrcFX, AECompiledShaderManager &refInstanceManager,
										const char *lpParamStr, AEINT32 nCreationFlags );

	/// \brief
	///  Destructor
	AE_DLLIMPEXP virtual ~AECompiledEffect( void );

	/// @}
	/** @name Access Compiled Techniques */
	/// @{
	/// \brief
	///   Find a compiled technique inside this effect that matches the specified configuration
	///
	/// This function loops through all compiled techniques in this effect and compares the
	/// inclusion/exclusion flags provided in the passed structure with each technique's flags.
	///
	/// The first matching technique is returned.
	///
	/// This feature is useful for providing variants of the same effect (e.g. with fog/without fog) and
	/// accessing these variants at runtime.
	///
	/// \param pConfig
	///   The config that is used to test compatibility
	///
	/// \param pGlobalConfig
	///   Optional second config, can be AENULL. If specified, both configs must be compatible.
	///
	/// \return
	///   AECompiledTechnique *pTechnique : The first technique that has a compatible config or AENULL
	AE_DLLIMPEXP AECompiledTechnique *FindCompatibleTechnique( const AETechniqueConfig *lpConfig, const AETechniqueConfig *lpGlobalConfig = AENULL );

	/// \brief
	///   Returns the first valid technique in this effect. Commonly used for effects that do not require variants (i.e., only have one technique).
	AE_DLLIMPEXP AECompiledTechnique *GetDefaultTechnique( void );

	/// \brief
	///   Returns the source effect resource object.
	AE_FORCEINLINE AEShaderEffectResource *GetSourceEffect( void ) const;

	/// \brief
	///   Returns the parameter string.
	AE_FORCEINLINE const char *GetParameterString( void ) const;

	/// \brief
	///   Static helper function to concatenate multiple parameter strings into one, removing duplicates and whitespaces
	///
	/// This funciton generates a new parameter string, that contains every unique parameter name once. If contained more
	/// than once inside one string or in distinct strings, the latter value will be used
	///
	/// \param szTarget
	///   The target string buffer. Must hold enough bytes for the the sum of all szParamList strings
	///
	/// \param szParamList
	///   The list of parameter string pointers (iListCount elements)
	///
	/// \param iListCount
	///   The number of list elements in szParamList
	AE_DLLIMPEXP static void ConcatAndNormalizeParameterString( char *lpTarget, const char **lppParamList, AEINT32 iListCount);

	/// \brief
	///   Helper function to parse a single parameter
	///
	/// \param szParamStr
	///   The parameter string.
	///
	/// \param param
	///   Parsed result.
	///
	/// \return The remaining parameter string (or AENULL if done).
	AE_DLLIMPEXP const char *ParseNextParameter( const char *lpParamStr, AEShaderParam &refParam ) const;

	/// @}
	/** @name Internal methods */
	/// @{
	/// \brief
	///   Internal function
	AE_DLLIMPEXP void RemoveCachedVersion( AECompiledTechnique *lpTechnique );

	/// \brief
	///   Internal function
	AE_DLLIMPEXP AECompiledTechnique *CompileTechnique( AEShaderEffectTechnique *lpTechnique, hkvLogInterface* pLog );

	/// \brief
	///   Internal function
	AE_DLLIMPEXP void RemoveEffectResourceReference( void );

	/// \brief
	///   Internal function
	AE_DLLIMPEXP void EnsureShaderProgramsAreValid( void );

  /// @}
};

#include "AECompiledEffect.inl"
#endif // _AECOMPILEDEFFECT_H_
